﻿#pragma once

#include <filesystem>

#include "Containers/String.h"
#include "Reflection/Reflection.h"
#include "Path.m.h"

RSTRUCT()
struct WHENGINE_API SPath
{
    ROBJECT
public:    
    SPath();

    SPath(const CString& InPath);

    SPath(const char32_t * InPath);

    SPath(const char * InPath);

    SPath(const std::filesystem::path& InPath);

    RFUNCTION(ScriptConstructor)
    void FromString(const CString& InStringExpression);
    
    RFUNCTION()
    CString ToString() const ;


    RPROPERTY(Name="StringExpression",Getter="ToString",Setter="FromString")

    SPath RemoveFinalExtension() const;

    //get parent directory
    //return empty if cant find parent
    RFUNCTION()
    SPath Parent() const;

    //append path
    RFUNCTION()
    void Append(const SPath& WillBeAppendded) ;

    RFUNCTION()
    void Append(const CString& WillBeAppendded) ;

    RFUNCTION()
    static SPath Combine(const SPath& Left,const SPath& Right);

    void operator /= (const SPath& WillBeAppendded);
    SPath operator / (const SPath& WillBeAppendded) const;

    bool operator == (const SPath& Right) const ;

    RFUNCTION()
    bool IsSameWith(const SPath& Other) const;

    RFUNCTION()
    bool IsEmpty() const;

    //return error message if this is not a valid file name
    static CString IsValidFileOrFolderName(const CString& InName);

    //return error message if this is not a valid file name
    RFUNCTION()
    CString HasValidFileOrFolderName() const;

    //if the file or folder name is invalid
    //might cause crash when invoke Exists();
    //so we need to check this with HasValidFileOrFolderName() before Exists()
    //if the file or folder name is created by user input.
    RFUNCTION()
    bool Exists() const;

    RFUNCTION()
    bool Delete() const;

    RFUNCTION()
    SPath GetRelativeTo(const SPath & Base) const;

    //if this is a subfolder/file in InFolder
    //include the case that this is grandchild of InFolder
    RFUNCTION()
    bool IsInside(const SPath & InFolder) const;

    RFUNCTION()
    SPath ToAbsolute() const;

    std::filesystem::path GetLowLevel() const;

    RFUNCTION()
    bool IsDirectory() const;

    RFUNCTION()
    bool IsFile() const;

    bool IsEmptyDirectory() const;

    //get all files in this directory
    //this must be a directory
    TVector<SPath> ListFiles() const;

    //get all subdirectories in this directory
    //this must be a directory
    TVector<SPath> ListSubDirectories() const;

    //@Extension , for example ".png" 
    bool IsFileWithExtension(const CString& Extension,bool IgnoreCase=true) const;

    //是不是资产文件
    bool IsAssetFile() const;

    void SetExtension(const CString& Extension);

    TOptional<CString> GetExtension() const;

    // get file name without any extension
    CString GetBaseFileName() const;

    CString GetFileOrDirectoryName() const;
    
    uint64_t GetHashCode()  const
    {
        return ToString().GetHashCode();
    }

private:
    std::filesystem::path LowLevel;

};

